home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / INFO / INTER39D.ZIP / INTPRINT.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  40KB  |  1,504 lines

  1. /************************************************************************/
  2. /* INTPRINT.C by Ralf Brown.  Donated to the Public Domain.        */
  3. /* Please do not remove my name from any copies or derivatives.        */
  4. /************************************************************************/
  5. /* Program History:                            */
  6. /*   v1.00  4/23/89  initial public release                */
  7. /*             with 4/30/89 list                    */
  8. /*   v1.10  5/21/89  added -I and -f                    */
  9. /*   v1.11  1/6/90   fixed #endif's for compilers which don't handle    */
  10. /*             labels                        */
  11. /*   v1.20  6/8/90   added -r                        */
  12. /*   v1.30  7/14/90  added -b, tables now stay aligned on odd indents    */
  13. /*   v1.40  10/6/90  added -B based on changes by Naoto Kimura, -w    */
  14. /*   v1.40a 5/6/91   HP LaserJet II support by Russ Herman        */
  15. /*   v1.41  7/9/91   HP PCL support by P.J.Farley III            */
  16. /*   v2.00  9/1/91   modular printer definitions            */
  17. /*             printing multipart interrupt list            */
  18. /*   v2.01  2/9/92   fixed summary entry for non-numeric AX= and AH=    */
  19. /*             smarter page breaks                */
  20. /*   v2.02  2/18/92  bugfix & isxdigit suggested by Aaron West        */
  21. /*   v2.10  3/14/92  updated to handle extra flags in headings        */
  22. /*   v2.11  5/23/92  bugfix pointed out by Joe White            */
  23. /*   v2.20  6/12/92  added -F based on code by Richard Brittain     */
  24. /*             added -H and Panasonic printer def by Lewis Paper    */
  25. /*   v2.21  10/14/92 fixed error in -H/-r interaction            */
  26. /*             updated for new 'Bitmask of' section        */
  27. /*   v2.22   2/15/93 exclude Index: by default, -x to force inclusion    */
  28. /*             changed 'Bitmask of' to 'Bitfields for'            */
  29. /*   v2.23   5/24/93 fix to allow INT/AL= to appear correctly in summary*/
  30. /*   v2.24   7/15/93 -k and infinite-length pages by Bent Lynggaard     */
  31. /************************************************************************/
  32. /* Recompiling:                                */
  33. /*   Turbo C / Borland C++                        */
  34. /*    tcc -mt -lt -Z -p intprint                    */
  35. /************************************************************************/
  36.  
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <ctype.h>
  40.  
  41. #define VERSION "2.24"
  42.  
  43. #ifdef __TURBOC__
  44. #  define PROTOTYPES
  45. #  include <stdlib.h>
  46.    int _Cdecl isatty(int handle) ;
  47.    void _setenvp(void) {} /* don't need the environment, so don't include it */
  48. #else
  49.  
  50. /* not Turbo C / Borland C, so set configuration #defines */
  51. #if 0  /* set to 1 if compiler supports ANSI-style prototypes, 0 otherwise */
  52. #define PROTOTYPES
  53. #endif
  54. #if 1  /* set to 0 if library contains strnicmp(), 1 otherwise */
  55. #define NEED_STRNICMP
  56. #endif
  57. #if 1  /* set to 0 if library contains isxdigit(), 1 otherwise */
  58. #define NEED_ISXDIGIT
  59. #endif
  60. #if 0  /* set to 0 if library contains strdup(), 1 otherwise */
  61. #define NEED_STRDUP
  62. #endif
  63. #if 1  /* set to 0 if library contains strupr(), 1 otherwise */
  64. #define NEED_STRUPR
  65. #endif
  66. #if 1  /* set to 0 if library contains three-arg itoa(), 1 otherwise */
  67. #define NEED_ITOA
  68. #endif
  69.  
  70. #define _Cdecl
  71.  
  72. #endif /* __TURBOC__ */
  73.  
  74. /***********************************************/
  75.  
  76. #ifndef FALSE
  77. #define FALSE 0
  78. #endif
  79. #ifndef TRUE
  80. #define TRUE !FALSE
  81. #endif
  82.  
  83. #define MAXLINE 81   /* at most 80 chars per line (plus newline) */
  84. #define MAXPAGE 200  /* at most 200 lines per page */
  85.  
  86. #define start_of_entry(s) (strncmp(s,"INT ",4) == 0)
  87. #define divider_line(line) (strncmp(line,"--------",8) == 0)
  88.  
  89. /***********************************************/
  90.  
  91. typedef struct _cstr         /* a counted string */
  92.    {
  93.    int len ;             /* the string's length */
  94.    char *str ;             /* the actual contents of the string */
  95.    } cstr ;
  96.  
  97. #define CSTR(s) { sizeof(s)-1, (s) }  /* for defining a counted string literal */
  98. #define cstrlen(s) ((s)->len)     /* how long is the counted string? */
  99. #define cstrchar(s,i) ((s)->str[i])  /* retrieve a character from a counted string */
  100.  
  101. typedef struct _printer_def
  102.    {
  103.    char *name ;            /* for selecting the appropriate printer */
  104.    cstr init1, init2 ;        /* initialization strings */
  105.    cstr marginl, marginc, marginr ; /* margins: duplex even, non-duplex, duplex odd */
  106.    cstr duplex_on ;        /* turn on duplex mode */
  107.    cstr term1, term2 ;        /* cleanup strings */
  108.    cstr bold_on, bold_off ;    /* boldface on/off */
  109.    int indent ;            /* how many extra spaces to indent */
  110.    int lines_per_page ;        /* how many lines to print on each page */
  111.    int page_length ;        /* how many lines on each page */
  112.    int page_width ;        /* how many printable columns per line? */
  113. #ifdef PROTOTYPES
  114.    void (*put_line)(FILE *,int) ;/* function to call to print out divider line */
  115.    void (*set_typeface)(FILE *,char *) ;
  116. #else
  117.    void (*put_line)() ;        /* function to call to print out divider line */
  118.    void (*set_typeface)() ;
  119. #endif /* PROTOTYPES */
  120.    int *flag ;            /* flag to set when using this printer definition */
  121.    } PRINTER_DEF ;
  122.  
  123. struct filter_list
  124.    {
  125.    struct filter_list *next ;
  126.    char *str ;
  127.    } ;
  128.  
  129. typedef struct _header
  130.    {
  131.    int part ;
  132.    int first_on_page ; /* TRUE if a new entry starts at the top of the page */
  133.    char desc[24] ;
  134.    } HEADER ;
  135.  
  136. /***********************************************/
  137.  
  138. #ifdef PROTOTYPES
  139. void usage(void) ;
  140. void fatal(char *msg) ;
  141. void get_raw_line(char *buf,int size) ;
  142. int unwanted_section(char *buf) ;
  143. void get_line(char *buf,int size) ;
  144. void indent_line(FILE *fp) ;
  145. void indent_to(int where,FILE *fp) ;
  146. void put_line(FILE *fp, int len) ;
  147. void HPPCL_put_line(FILE *fp, int len) ;
  148. void HPPCL_set_typeface(FILE *fp,char *typeface) ;
  149. void fputcstr(cstr *s, FILE *fp) ;
  150. int section_start(char *line) ;
  151. int start_of_table(char *line) ;
  152. void output_line(char *line,FILE *fp) ;
  153. void fill_buffer(int lines, int lines_per_page) ;
  154. int find_page_break(int lines) ;
  155. void summarize(FILE *summary, int line, int pages_printed) ;
  156. void start_format(char *line) ;
  157. struct filter_list *add_filter_info(struct filter_list *list,char *str) ;
  158. void build_filter_lists(char *file) ;
  159. void print_line(char *line) ;
  160. void make_description(char *desc,int line) ;
  161. char *determine_heading(int last) ;
  162. void print_buffer(int last, int lines_per_page, int total_lines, int use_FF) ;
  163. void select_printer(char *name) ;
  164. void display_printers(void) ;
  165. int _Cdecl main(int argc, char **argv) ;
  166. #else
  167. void put_line() ;
  168. void HPPCL_put_line() ;
  169. #endif /* PROTOTYPES */
  170.  
  171. /***********************************************/
  172.  
  173. FILE *infile, *outfile ;
  174. char *input_file ;
  175.  
  176. char buffer[MAXPAGE][MAXLINE] ;
  177. char num[6] ;
  178. char summary_line[2*MAXLINE] ;
  179.  
  180. int pages_printed = 0 ;
  181. int page_width = 0 ;        /* page width in characters, 0 = use prtdef */
  182. int indent = 0 ;        /* number of blanks to add at start of each line */
  183. int widow_length = 10 ;        /* number of lines to scan for good place to break */
  184. int page_numbers = FALSE ;    /* add page numbers to bottom of page? */
  185. int multi_file = FALSE ;    /* printing multipart interrupt list? */
  186. int out_of_files = FALSE ;    /* hit end of last file for multipart printing? */
  187. int do_summary = FALSE ;    /* create a one-line-per-call summary? */
  188. int do_formats = FALSE ;    /* create a separate file with data structures? */
  189. int do_filter = FALSE ;        /* using a filtering file? */
  190. int do_headers = FALSE ;    /* add page headings? */
  191. int include_index_lines = FALSE ;
  192. int IBM_chars = FALSE ;        /* printer can handle IBM graphics characters */
  193. int boldface = FALSE ;        /* boldface titles and Return:/Notes: ? */
  194. int printer_bold = FALSE ;    /* boldface using printer control sequences? */
  195. int echo_format = FALSE ;
  196. int duplex = FALSE ;
  197. int HPPCL_mode = FALSE ;
  198. int keep_divider_lines = FALSE ;
  199. FILE *summary ;
  200. FILE *formats ;
  201. PRINTER_DEF *printer = NULL ;
  202.  
  203. unsigned int first_page = 0 ;
  204. unsigned int last_page = ~0 ;
  205.  
  206. struct filter_list *includes = NULL ;
  207. struct filter_list *excludes = NULL ;
  208.  
  209. HEADER header_first = { 0, FALSE, "" } ;
  210. HEADER header_last = { 0, FALSE, "" } ;
  211.  
  212. /***********************************************/
  213.  
  214. PRINTER_DEF printers[] =
  215.    {
  216.      { "default",
  217.        CSTR(""), CSTR(""),
  218.        CSTR(""), CSTR(""), CSTR(""),
  219.        CSTR(""),
  220.        CSTR(""), CSTR(""),
  221.        CSTR(""), CSTR(""),
  222.        -1,
  223.        60,
  224.        0,
  225.        79,
  226.        put_line,
  227.        NULL,
  228.        NULL,
  229.      },
  230.      { "Epson FX80, 12 cpi",
  231.        CSTR("\033M"), CSTR(""),
  232.        CSTR("\033l\004"), CSTR("\033l\007"), CSTR("\033l\014"),
  233.        CSTR(""),
  234.        CSTR("\033P"), CSTR("\033l\000"),
  235.        CSTR("\033E"), CSTR("\033F"),
  236.        0,
  237.        60,
  238.        0,
  239.        87,    /* 96 - left margin - 1 right margin */
  240.        put_line,
  241.        NULL,
  242.        NULL,
  243.      },
  244.      { "Panasonic KX-P1124i / 10 cpi Epson",
  245.        CSTR(""), CSTR(""),
  246.        CSTR(""), CSTR(""), CSTR(""),
  247.        CSTR(""),
  248.        CSTR(""), CSTR(""),
  249.        CSTR("\033E"), CSTR("\033F"),
  250.        -1,
  251.        60,
  252.        0,
  253.        79,
  254.        put_line,
  255.        NULL,
  256.        NULL,
  257.      },
  258.      { "HP PCL",
  259.        CSTR("\033(8U"), CSTR(""),
  260.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  261.        CSTR("\033&l1S"),
  262.        CSTR("\033E"), CSTR(""),
  263.        CSTR("\033(s3B"), CSTR("\033(s0B"),
  264.        0,
  265.        69,
  266.        0,
  267.        87,    /* 96 - left margin - 1 right margin */
  268.        HPPCL_put_line,
  269.        HPPCL_set_typeface,
  270.        &HPPCL_mode,
  271.      },
  272. #define HPPCL_FONT_ON_A "\033(s0p12h10v0s0b"
  273. /* HP PCL4/5 Font select: Roman-8;Upright12Pitch10PointMediumWeight */
  274. #define HPPCL_FONT_ON_B "T\033&l6.8571C"
  275. /* HP PCL4/5 Font select: End typeface select;VMI=7LPI: (48/7)-48th's inches*/
  276. #define HPPCL_IBM_LN_A    "\033&f0S\033*p-15Y\033*c"
  277. /* HP PCL4/5 IBM Line:    Push Pos;Up 15/720";Hor.Rule ???/300ths" long */
  278. #define HPPCL_IBM_LN_B    "a3b0P\033&f1S"
  279. /* HP PCL4/5 IBM Line:     3/300ths" high,Print rule;Pop Position */
  280.      { "LaserJet II",
  281.        CSTR("\033(10U"),CSTR(""),
  282.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  283.        CSTR(""),
  284.        CSTR("\033E"),CSTR(""),
  285.        CSTR("\033(s3B"),CSTR("\033(s0B"),
  286.        0,
  287.        54,
  288.        60,
  289.        79,
  290.        put_line,
  291.        NULL,
  292.        &IBM_chars,
  293.      },
  294.    } ;
  295. #define NUM_PRINTERS (sizeof(printers)/sizeof(printers[0]))
  296.  
  297. /***********************************************/
  298.  
  299. #ifdef NEED_STRNICMP
  300. #ifdef PROTOTYPES
  301. int strnicmp(char *s1,char *s2,int len)
  302. #else
  303. int strnicmp(s1,s2,len)
  304. char *s1,*s2 ;
  305. unsigned int len ;
  306. #endif PROTOTYPES
  307. {
  308.    char c1, c2 ;
  309.  
  310.    while (*s1 && *s2 && len > 0)
  311.       {
  312.       len-- ;
  313.       c1 = (islower(*s1) ? toupper(*s1) : *s1) ;
  314.       c2 = (islower(*s2) ? toupper(*s2) : *s2) ;
  315.       if (c1 != c2 || len == 0)     /* mismatch or substrings exhausted? */
  316.      return (c1 - c2) ;
  317.       s1++ ;
  318.       s2++ ;
  319.       }
  320.    return 0 ;  /* strings match exactly on first 'len' characters */
  321. }
  322. #endif /* NEED_STRNICMP */
  323.  
  324. #ifdef NEED_STRUPR
  325. #ifdef PROTOTYPES
  326. char *strupr(char *s)
  327. #else
  328. char *strupr(s)
  329. char *s ;
  330. #endif /* PROTOTYPES */
  331. {
  332.    char *orig_s = s ;
  333.    char c ;
  334.    
  335.    if (s)
  336.       while (*s)
  337.      {
  338.      c = *s ;      
  339.      *s++ = (islower(c) ? toupper(c) : c) ;
  340.      }
  341.    return orig_s ;
  342. }
  343. #endif /* NEED_STRUPR */
  344.  
  345. #ifdef NEED_STRDUP
  346. #ifdef PROTOTYPES
  347. char *strdup(char *s)
  348. #else
  349. char *strdup(s)
  350. char *s ;
  351. #endif /* PROTOTYPES */
  352. {
  353.    char *copy ;
  354.       
  355.    if (s)
  356.       copy = (char *)malloc(strlen(s)+1) ;
  357.    else
  358.       copy = NULL ;   
  359.    if (copy)
  360.       strcpy(copy,s) ;
  361.    return copy ;
  362. }
  363. #endif /* NEED_STRDUP */
  364.  
  365. #ifdef NEED_ISXDIGIT
  366. #ifdef PROTOTYPES
  367. int isxdigit(int c)
  368. #else
  369. int isxdigit(c)
  370. int c ;
  371. #endif /* PROTOTYPES */
  372. {
  373.    return isdigit(c) || (strchr("ABCDEFabcdef",c) != NULL) ;
  374. }
  375. #endif /* NEED_ISXDIGIT */
  376.  
  377. #ifdef NEED_ITOA
  378. #ifdef PROTOTYPES
  379. char *itoa(int num,char *buf,int radix)
  380. #else
  381. char *itoa(num,buf,radix)   /* not everybody has the same itoa() as TurboC */
  382. int num ;            /* minimal implementation */
  383. char *buf ;
  384. int radix ;
  385. #endif /* PROTOTYPES */
  386. {
  387.    int count = 0 ;
  388.    int i ; 
  389.    char tmp ;
  390.  
  391.    do {
  392.       buf[count++] = '0' + num % radix ;
  393.       num = num / radix ;
  394.    } while (num) ;
  395.    buf[count] = '\0' ;
  396.    if (count > 1)
  397.       for (i = 0 ; i < count / 2 ; i++)
  398.      {
  399.      tmp = buf[i] ;
  400.      buf[i] = buf[count-i-1] ;
  401.      buf[count-i-1] = tmp ;
  402.      }
  403.    return buf ;
  404. }
  405. #endif /* NEED_ITOA */
  406.  
  407. /***********************************************/
  408.  
  409. void usage()
  410. {
  411.    fputs("\
  412. Usage: intprint [options] intlist [>|>>]output\n\
  413. Options:\n\
  414. \t-b\tboldface title lines and section headings\n\
  415. \t-B\tboldface using printer control codes instead of overprinting\n\
  416. \t-d\t(duplex) print even/odd pages with different indents\n\
  417. \t-e\tassume 'elite' mode (96 chars per line) for default printer\n\
  418. \t-ffile\twrite all data structure formats to 'file'\n\
  419. \t-Ffile\tprint only entries matching filtering info in 'file'\n\
  420. \t-H\tadd page headers showing interrupt call(s) on page\n\
  421. \t-iN\tindent output N spaces (overridden by some printers)\n\
  422. \t-I\tprinter supports IBM graphics characters\n\
  423. \t-k\tkeep original divider lines\n\
  424. \t-lN\tprint N lines per page (default varies by prntr, 0=infinite)\n\
  425. \t-LN\tassume N lines on a page, use linefeeds if > #lines printed\n\
  426. \t-m\tlist is in multiple parts starting with the named file\n\
  427. \t-nN\tassume N pages have been printed from previous parts\n\
  428. \t-p\tadd page numbers\n\
  429. \t-Pname\tassume printer 'name' (-P? lists supported printers)\n\
  430. \t-rN:M\tprint only pages N through M\n\
  431. \t-sfile\twrite a one-line-per-function summary to 'file'\n\
  432. \t-tN\tselect typeface N for the chosen printer\n\
  433. \t-wN\tscan N lines from bottom of page for good place to break\n\
  434. \t-x\tinclude Index: lines in formatted output\n"
  435.     ,stderr) ;
  436.    exit(1) ;
  437. }
  438.  
  439. /***********************************************/
  440.  
  441. void fatal(msg)
  442. char *msg ;
  443. {
  444.    fputs(msg,stderr) ;
  445.    fputs("\n",stderr) ;
  446.    exit(1) ;
  447. }
  448.  
  449. /***********************************************/
  450.  
  451. void indent_line(fp)
  452. FILE *fp ;
  453. {
  454.    int ind = indent ;
  455.  
  456.    while (ind >= 8)
  457.       {
  458.       fputc('\t',fp) ;
  459.       ind -= 8 ;
  460.       }
  461.    while (ind-- > 0)
  462.       fputc(' ', fp) ;
  463. }
  464.  
  465. /***********************************************/
  466.  
  467. void indent_to(where,fp)
  468. int where ;
  469. FILE *fp ;
  470. {
  471.    where += indent ;
  472.    
  473.    while (where >= 8)
  474.       {
  475.       fputc('\t',fp) ;
  476.       where -= 8 ;
  477.       }
  478.    while (where-- > 0)
  479.       fputc(' ', fp) ;
  480. }
  481.  
  482. /***********************************************/
  483.  
  484. void put_line(fp,len)
  485. FILE *fp ;
  486. int len ;
  487. {
  488.    int i ;
  489.  
  490.    if (IBM_chars)
  491.       for (i = 0 ; i < len ; i++)
  492.      fputc(196,fp) ;  /* single horizontal line */
  493.    else
  494.       for (i = 0 ; i < len ; i++)
  495.      fputc('-',fp) ;
  496. }
  497.  
  498. /***********************************************/
  499.  
  500. void HPPCL_put_line(fp,len)
  501. FILE *fp ;
  502. int len ;
  503. {
  504.    fputs(HPPCL_IBM_LN_A,fp) ;
  505.    itoa((len * 25), num, 10) ;
  506.    fputs(num,fp) ;
  507.    fputs(HPPCL_IBM_LN_B,fp) ;
  508. }
  509.  
  510. /***********************************************/
  511.  
  512. void HPPCL_set_typeface(fp,typeface)
  513. FILE *fp ;
  514. char *typeface ;
  515. {
  516.    fputs(HPPCL_FONT_ON_A,fp) ;
  517.    if (typeface)
  518.       fputs(typeface,fp) ;
  519.    else
  520.       fputs("8",fp) ;
  521.    fputs(HPPCL_FONT_ON_B,fp) ;
  522. }
  523.  
  524. /***********************************************/
  525.  
  526. void fputcstr(s,fp)        /* output the counted string to the given file */
  527. FILE *fp ;
  528. cstr *s ;
  529. {
  530.    int i ;
  531.  
  532.    for (i = 0 ; i < cstrlen(s) ; i++)
  533.       fputc(cstrchar(s,i),fp) ;
  534. }
  535.  
  536. /***********************************************/
  537.  
  538. int section_start(line)
  539. char *line ;
  540. {
  541.    return (strncmp(line,"Return:",7) == 0 ||
  542.        strncmp(line,"Desc:",5) == 0 ||
  543.        strncmp(line,"Note:",5) == 0 ||
  544.        strncmp(line,"Notes:",6) == 0 ||
  545.        strncmp(line,"SeeAlso:",8) == 0 ||
  546.        strncmp(line,"BUG:",4) == 0 ||
  547.            strncmp(line,"BUGS:",5) == 0 ||
  548.        strncmp(line,"Program:",8) == 0 ||
  549.        strncmp(line,"Index:",6) == 0
  550.       ) ;
  551. }
  552.  
  553. /***********************************************/
  554.  
  555. int start_of_table(line)
  556. char *line ;
  557. {
  558.    return (strncmp(line,"Format of ",10) == 0 ||
  559.            strncmp(line,"Values ",7) == 0 ||
  560.            strncmp(line,"Call ",5) == 0 ||
  561.        strncmp(line,"Bitfields for ",14) == 0 ||
  562.        strcmp(strchr(line,'\0')-12,"called with:") == 0
  563.           ) ;
  564. }
  565.    
  566. /***********************************************/
  567.  
  568. void output_line(line,fp)
  569. char *line ;
  570. FILE *fp ;
  571. {
  572.    int pos = 0 ;
  573.    char bold[10] ;
  574.  
  575.    if (boldface)
  576.       {
  577.       if (start_of_entry(line) || start_of_table(line))
  578.      {
  579.      indent_line(fp) ;
  580.      if (printer_bold)
  581.         {
  582.         fputcstr(&printer->bold_on,fp) ;
  583.         fputs(line,fp) ;
  584.         fputcstr(&printer->bold_off,fp) ;
  585.         line = NULL ;
  586.         }
  587.      else
  588.         {
  589.         fputs(line,fp) ;
  590.         fputc('\r',fp) ;
  591.         }
  592.      }
  593.       else if (section_start(line))
  594.      {
  595.      strncpy(bold,line,sizeof bold) ;
  596.      *strchr(bold,':') = '\0' ;
  597.      indent_line(fp) ;
  598.      if (printer_bold)
  599.         {
  600.         fputcstr(&printer->bold_on,fp) ;
  601.         fputs(bold,fp) ;
  602.         fputcstr(&printer->bold_off,fp) ;
  603.         pos = strlen(bold) ;     /* we're no longer at the left edge of the */
  604.         line += pos ;         /* line, so figure out where we are */
  605.         }
  606.      else
  607.         {
  608.         fputs(bold,fp) ;
  609.         fputc('\r',fp) ;
  610.         }
  611.      }
  612.       } /* boldface */
  613.    if (line && *line)
  614.       {
  615.       if (pos == 0)        /* are we currently at the left edge of the line? */
  616.      indent_line(fp) ;  /* if yes, indent the desired amount */
  617.       if (indent % 8)
  618.      {
  619.      while (*line)
  620.         {
  621.         if (*line == '\t')
  622.            do {
  623.           fputc(' ',fp) ;
  624.           } while (++pos % 8) ;
  625.         else
  626.            {
  627.            fputc(*line,fp) ;
  628.            pos++ ;
  629.            }
  630.         line++ ;
  631.         }
  632.      }
  633.       else
  634.      fputs(line,fp) ;
  635.       }
  636.    fputc('\n',fp) ;
  637. }
  638.  
  639. /***********************************************/
  640.  
  641. void get_raw_line(buf,size)
  642. char *buf ;
  643. int size ;
  644. {
  645.    int last ;
  646.  
  647.    buf[0] = '\0' ;
  648.    if (out_of_files)
  649.       return ;
  650.    fgets(buf,size,infile) ;
  651.    if ((feof(infile) || buf[0] == '\0'))
  652.       if (multi_file)
  653.      {
  654.      FILE *tempfile ;
  655.  
  656.      last = strlen(input_file) - 1 ;
  657.      input_file[last]++ ;
  658.      if ((tempfile = fopen(input_file,"r")) != NULL)
  659.         {
  660.         fclose(infile) ;
  661.         infile = tempfile ;
  662.         fgets(buf,size,infile) ;
  663.         }
  664.      else
  665.         {
  666.         out_of_files = TRUE ;
  667.         return ;
  668.         }
  669.      }
  670.       else
  671.      out_of_files = TRUE ;
  672.    last = strlen(buf) - 1 ;
  673.    while (last >= 0 && (buf[last] == '\n' || buf[last] == '\r'))
  674.       buf[last--] = '\0' ;
  675. }
  676.  
  677. /***********************************************/
  678.  
  679. int unwanted_section(buf)
  680. char *buf ;
  681. {
  682.    int unwanted = FALSE ;
  683.    int found ;
  684.    char str[MAXLINE] ;
  685.    struct filter_list *p ;
  686.    
  687.    if (start_of_entry(buf)) /* is it an interrupt entry? */
  688.       {
  689.       strncpy(str,buf,sizeof str) ;
  690.       str[sizeof str - 1] = '\0' ;
  691.       (void) strupr(str) ;
  692.       /* set 'unwanted' to TRUE if *any* exclude string matches */
  693.       for (p = excludes ; p ; p = p->next)
  694.      {
  695.      if (p->str && strstr(str, p->str) != NULL)
  696.         {
  697.         unwanted = TRUE ;
  698.         break ;
  699.         }
  700.      }
  701.       /* if still wanted, set to TRUE if *no* include string matches */
  702.       if (!unwanted)
  703.      {
  704.      found = FALSE ;
  705.      for (p = includes ; p ; p = p->next)
  706.         {
  707.         if (p->str && strstr(str, p->str) != NULL)
  708.            {
  709.            found = TRUE ;
  710.            break ; 
  711.            }
  712.         }
  713.      if (!found)
  714.         unwanted = TRUE ;
  715.      }
  716.       }
  717.    return unwanted ;
  718. }
  719.  
  720. /***********************************************/
  721.  
  722. void get_line(buf,size)
  723. char *buf ;
  724. int size ;
  725. {
  726.    static char next_line[MAXLINE] ;
  727.    static int readahead = FALSE ;
  728.  
  729.    /* get the next line from the file, skipping unwanted entries */
  730.    if (readahead)
  731.       {
  732.       strncpy(buf,next_line,size) ;
  733.       buf[size-1] = '\0' ;
  734.       readahead = FALSE ;
  735.       }
  736.    else
  737.       {
  738.       do {
  739.      get_raw_line(buf,size) ;
  740.      } while (!include_index_lines && strncmp(buf,"Index:",6) == 0) ;
  741.       strncpy(next_line,buf,sizeof next_line);
  742.       next_line[sizeof next_line - 1] = '\0' ;
  743.       /* if we read a divider line, we have to look ahead */
  744.       while (do_filter && next_line[0] && divider_line(next_line))
  745.      {
  746.      strncpy(buf,next_line,size) ; /* we may be returning the divider */
  747.      buf[size-1] = '\0' ;
  748.      get_raw_line(next_line,sizeof next_line) ;
  749.      if (unwanted_section(next_line))
  750.         {
  751.         while (!divider_line(next_line))
  752.            get_raw_line(next_line,sizeof next_line) ;
  753.         }
  754.      else /* section is wanted, so return divider and then next line */
  755.         readahead = TRUE ;
  756.      }
  757.       }
  758. }
  759.  
  760. /***********************************************/
  761.  
  762. void fill_buffer(lines,lines_per_page)
  763. int lines, lines_per_page ;
  764. {
  765.    int i ;
  766.  
  767.    if (lines)
  768.       for (i = lines ; i < lines_per_page ; i++)
  769.      strcpy(buffer[i-lines], buffer[i]) ;
  770.    else
  771.       lines = lines_per_page ;
  772.    for (i = lines_per_page - lines ; i < lines_per_page ; i++)
  773.       get_line(buffer[i], sizeof(buffer[i])) ;
  774. }
  775.  
  776. /***********************************************/
  777.  
  778. int find_page_break(lines)
  779. int lines ;
  780. {
  781.    int i ;
  782.  
  783.    for (i = 0 ; i < widow_length ; i++)
  784.       {
  785.       if (strcmp(buffer[lines-i-1],"\n") == 0 ||
  786.       strlen(buffer[lines-i-1]) == 0 ||
  787.       divider_line(buffer[lines-i-1]) ||
  788.       section_start(buffer[lines-i]))
  789.      return lines - i ;
  790.       }
  791.    return lines ;
  792. }
  793.  
  794. /***********************************************/
  795.  
  796. void summarize(summary, line, pages_printed)
  797. FILE *summary ;
  798. int line, pages_printed ;
  799. {
  800.    char *s, reg ;
  801.    int i ;
  802.    int max_descrip ;
  803.    int len ;
  804.  
  805.    s = buffer[line] ;
  806.    if (start_of_entry(s))
  807.       {
  808.       strcpy(summary_line," -- -- -- ") ;
  809.       summary_line[1] = s[4] ;     /* output interrupt number */
  810.       summary_line[2] = s[5] ;
  811.       len = 4 ;
  812.       s = buffer[line+1] ;
  813.       while (*s && isspace(*s))
  814.      s++ ;
  815.       if (*s == 'A')
  816.      {
  817.      reg = s[1] ;
  818.      while (*s && *s != '=')
  819.         s++ ;
  820.      s++ ;        /* skip the equal sign */
  821.      while (*s && isspace(*s))
  822.         s++ ;    /* skip the space between equal sign and number */
  823.      if (isxdigit(*s) && isxdigit(s[1]))
  824.         {
  825.         if (reg == 'L')
  826.            len += 3 ;
  827.         summary_line[len++] = *s++ ;
  828.         summary_line[len++] = *s++ ;
  829.         if (reg == 'X')
  830.            {
  831.            len++ ;
  832.            summary_line[len++] = *s++ ;
  833.            summary_line[len] = *s ;
  834.            }
  835.         }
  836.      }
  837.       len = 10 ;
  838.       if (page_numbers)
  839.      {
  840.      itoa(pages_printed,num,10) ;
  841.      for (i = strlen(num) ; i < 3 ; i++)
  842.         summary_line[len++] = ' ' ;
  843.      strcpy(summary_line+len,num) ;
  844.      len += strlen(num) ;
  845.      summary_line[len++] = ' ' ;
  846.      }
  847.       s = buffer[line] + 7 ;    /* find function description */
  848.       if (*s && *s != '-')    /* does the heading contain flags? */
  849.      {
  850.      while (*s && !isspace(*s))
  851.         summary_line[len++] = *s++ ;
  852.      summary_line[len++] = '>' ;
  853.      summary_line[len++] = ' ' ;
  854.      while (*s && *s != '-')
  855.         s++ ;
  856.      }
  857.       while (*s && !isspace(*s))
  858.      s++ ;
  859.       while (*s && isspace(*s))
  860.      s++ ;
  861.       max_descrip = (page_width > sizeof(summary_line)-1) ? 
  862.                    sizeof(summary_line)-1 : page_width ;
  863.       while (len < max_descrip && *s)
  864.      summary_line[len++] = *s++ ;
  865.       summary_line[len] = '\0' ;
  866.       if (do_summary && summary)
  867.      output_line(summary_line,summary) ;
  868.       }
  869. }
  870.  
  871. /***********************************************/
  872.  
  873. void start_format(line)
  874. char *line ;
  875. {
  876.    indent_line(formats) ;
  877.    (*printer->put_line)(formats,79) ;
  878.    fputc('\n',formats) ;
  879.    indent_line(formats) ;
  880.    fputs(summary_line,formats) ;
  881.    fputc('\n',formats) ;
  882.    indent_line(formats) ;
  883.    fputc('\t',formats) ;
  884.    fputs(line+10,formats) ;
  885.    fputc('\n',formats) ;
  886.    echo_format = TRUE ;
  887. }
  888.  
  889. /***********************************************/
  890.  
  891. void print_line(line)
  892. char *line ;
  893. {
  894.    if (*line)
  895.       {
  896.       if (!keep_divider_lines && divider_line(line))
  897.      {
  898.      indent_line(outfile) ;
  899.      (*printer->put_line)(outfile,79) ;
  900.      fputc('\n', outfile) ;
  901.      echo_format = FALSE ;
  902.      }
  903.       else
  904.      {
  905.      output_line(line, outfile) ;
  906.      if (echo_format)
  907.         output_line(line,formats) ;
  908.      }
  909.       }
  910.    else
  911.       {
  912.       fputc('\n', outfile) ;
  913.       echo_format = FALSE ;
  914.       }
  915. }
  916.  
  917. /***********************************************/
  918.  
  919. void make_description(desc,line)
  920. char *desc ;
  921. int line ;
  922. {
  923.    summarize(NULL,line,0) ;
  924.    memcpy(desc,"INT ", 4) ;
  925.    desc += 4 ;
  926.    *desc++ = summary_line[1] ;
  927.    *desc++ = summary_line[2] ;
  928.    if (summary_line[4] != '-')
  929.       {
  930.       memcpy(desc,", AH=", 5) ;
  931.       desc += 5 ;
  932.       *desc++ = summary_line[4] ;
  933.       *desc++ = summary_line[5] ;
  934.       }
  935.    if (summary_line[7] != '-')
  936.       {
  937.       memcpy(desc,", AL=", 5) ;
  938.       desc += 5 ;
  939.       *desc++ = summary_line[7] ;
  940.       *desc++ = summary_line[8] ;
  941.       }
  942.    *desc = '\0' ;
  943. }
  944.  
  945. /***********************************************/
  946.  
  947. char *determine_heading(last)
  948. int last ;
  949. {
  950.    int i ;
  951.    static char heading[MAXLINE] ;
  952.    char num[10] ;
  953.    
  954.    if (start_of_entry(buffer[0]))
  955.       {
  956.       make_description(header_first.desc,0) ;
  957.       header_first.part = 1 ;
  958.       header_first.first_on_page = TRUE ;
  959.       }
  960.    else if (header_last.part == 0)  /* very first entry? */
  961.       {
  962.       for (i = 0 ; i < last ; i++)
  963.      if (start_of_entry(buffer[i]))
  964.         {
  965.         make_description(header_first.desc,i) ;
  966.         header_first.part = 1 ;
  967.         header_first.first_on_page = TRUE ;
  968.         break ;
  969.         }
  970.       }
  971.    else
  972.       {
  973.       strcpy(header_first.desc,header_last.desc) ;
  974.       header_first.part = header_last.part + 1 ;
  975.       header_first.first_on_page = FALSE ;
  976.       }
  977.    /* assume entry spans entire page */
  978.    strcpy(header_last.desc,header_first.desc) ;
  979.    header_last.part = header_first.part ;
  980.    header_last.first_on_page = header_first.first_on_page ;
  981.    /* find last entry on page */
  982.    if (header_first.part > 0)
  983.       {
  984.       for (i = last-1 ; i > 0 ; i--)
  985.      if (start_of_entry(buffer[i]))
  986.         {
  987.         make_description(header_last.desc,i) ;
  988.         header_last.part = 1 ;
  989.         header_last.first_on_page = FALSE ;
  990.         break ;
  991.         }
  992.       strcpy(heading,header_first.desc) ;
  993.       if (header_first.part > 1)
  994.      {
  995.      strcat(heading," (Part ") ;
  996.      itoa(header_first.part,num,10) ;
  997.      strcat(heading,num) ;
  998.      strcat(heading,")") ;
  999.      }
  1000.       if (strcmp(header_first.desc,header_last.desc) != 0 ||
  1001.       header_first.part != header_last.part)
  1002.      {
  1003.      strcat(heading," to ") ;
  1004.      strcat(heading,header_last.desc) ;
  1005.      if (header_last.part > 1)
  1006.         {
  1007.         strcat(heading," (Part ") ;
  1008.         itoa(header_last.part,num,10) ;
  1009.         strcat(heading,num) ;
  1010.         strcat(heading,")") ;
  1011.         }
  1012.      }
  1013.       return heading ; 
  1014.       }
  1015.    else /* no headings yet */
  1016.       return NULL ;
  1017. }
  1018.  
  1019. /***********************************************/
  1020.  
  1021. void print_buffer(last,lines_per_page,total_lines,use_FF)
  1022. int last, lines_per_page, total_lines ;
  1023. int use_FF ;
  1024. {
  1025.    int i ;
  1026.  
  1027.    pages_printed++ ;
  1028.    if (do_headers)
  1029.       {
  1030.       char *heading ;
  1031.       
  1032.       if ((heading = determine_heading(last)) != NULL)
  1033.      {
  1034.      if (pages_printed >= first_page && pages_printed <= last_page)
  1035.         {
  1036.         indent_to(40-strlen(heading)/2,outfile) ;
  1037.         if (boldface)
  1038.            {
  1039.            if (printer_bold)
  1040.           {
  1041.           fputcstr(&printer->bold_on,outfile) ;
  1042.           fputs(heading,outfile) ;
  1043.           fputcstr(&printer->bold_off,outfile) ;
  1044.           }
  1045.            else
  1046.           {
  1047.           fputs(heading,outfile) ;
  1048.           fputc('\r',outfile) ;
  1049.           indent_to(40-strlen(heading)/2,outfile) ;
  1050.           fputs(heading,outfile) ;
  1051.           }
  1052.            }
  1053.         else
  1054.            fputs(heading,outfile) ;
  1055.         }
  1056.      }
  1057.       fputs("\n\n",outfile) ;
  1058.       }
  1059.    for (i = 0 ; i < last ; i++)
  1060.       {
  1061.       if (pages_printed >= first_page && pages_printed <= last_page)
  1062.      print_line(buffer[i]) ;
  1063.       if (do_summary || do_formats)  /* need summary lines if doing formats */
  1064.      summarize(summary,i,pages_printed) ;
  1065.       if (do_formats && strncmp(buffer[i],"Format of ",10) == 0)
  1066.      start_format(buffer[i]) ;
  1067.       }
  1068.    if (pages_printed >= first_page && pages_printed <= last_page)
  1069.       {
  1070.       if (page_numbers)
  1071.      {
  1072.      for (i = last ; i < lines_per_page - 1 ; i++)
  1073.         fputc('\n', outfile) ;
  1074.      indent_to(38,outfile) ;
  1075.      fputs("- ", outfile) ;
  1076.      itoa(pages_printed, num, 10) ;
  1077.      fputs(num, outfile) ;
  1078.      fputs(" -\n", outfile) ;
  1079.      }
  1080.       if (use_FF)
  1081.      fputc('\f', outfile) ;
  1082.       else
  1083.      for (i = page_numbers?lines_per_page:last ; i<total_lines ; i++)
  1084.         fputc('\n', outfile) ;
  1085.       if (duplex)
  1086.      {
  1087.      if ((pages_printed % 2) == 1)    /* next page even or odd? */
  1088.         fputcstr(&printer->marginl, outfile) ;    /* even page */
  1089.      else
  1090.         fputcstr(&printer->marginr, outfile) ;    /* odd page */
  1091.      }
  1092.       }
  1093. }
  1094.  
  1095. /***********************************************/
  1096.  
  1097. void display_printers()
  1098. {
  1099.    int i ;
  1100.    
  1101.    fputs("Valid printer names are:\n",stderr) ;
  1102.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1103.       {
  1104.       fputc('\t',stderr) ;
  1105.       fputs(printers[i].name,stderr) ;
  1106.       fputc('\n',stderr) ;
  1107.       }
  1108.    fputs("When entering the printer name, use either a dash or an underscore\n",stderr) ;
  1109.    fputs("in place of blanks.  Case is ignored, and the name may be abbreviated\n",stderr) ;
  1110.    fputs("to the shortest unique prefix.\n",stderr) ;
  1111.    exit(1) ;
  1112. }
  1113.  
  1114. /***********************************************/
  1115.  
  1116. void select_printer(name)
  1117. char *name ;
  1118. {
  1119.    int i, len, prt = -1 ;
  1120.    
  1121.    len = strlen(name) ;
  1122.    for (i = 0 ; i < len ; i++)        /* convert dashes and underscores to blanks */
  1123.       if (name[i] == '-' || name[i] == '_')
  1124.      name[i] = ' ' ;
  1125.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1126.       if (strnicmp(name,printers[i].name,strlen(name)) == 0)
  1127.      if (prt == -1)
  1128.         prt = i ;
  1129.      else
  1130.         fatal("Ambiguous printer name!  Use -P? to list printers.") ;
  1131.    if (prt == -1)
  1132.       fatal("Unknown printer name!  Use -P? to list printers.") ;
  1133.    else
  1134.       printer = &printers[prt] ;
  1135. }
  1136.  
  1137. /***********************************************/
  1138.  
  1139. struct filter_list *add_filter_info(list,str)
  1140. struct filter_list *list ;
  1141. char *str ;
  1142. {
  1143.    struct filter_list *new ;
  1144.    
  1145.    if ((new = (struct filter_list *)calloc(1,sizeof(struct filter_list))) != NULL)
  1146.       {
  1147.       new->next = list ;
  1148.       new->str = strupr(strdup(str)) ;
  1149.       if (new->str == NULL)
  1150.      new = NULL ;
  1151.       }
  1152.    if (new == NULL)
  1153.       {
  1154.       fputs("Error: out of memory\n",stderr) ;
  1155.       exit(1) ;
  1156.       }
  1157.    return new ;
  1158. }
  1159.  
  1160. /***********************************************/
  1161.  
  1162. void build_filter_lists(file)
  1163. char *file ;
  1164. {
  1165.    FILE *fp ;
  1166.    char buf[MAXLINE] ;
  1167.    int len ;
  1168.    
  1169.    if ((fp = fopen(file,"r")) == NULL)
  1170.       {
  1171.       fputs("Warning: unable to open filtering file, will print entire list.\n",stderr) ;
  1172.       do_filter = FALSE ;
  1173.       }
  1174.    else /* OK, file is open, so start reading */
  1175.       {
  1176.       while (!feof(fp))
  1177.      {
  1178.      buf[0] = '\0' ;
  1179.      if (fgets(buf, sizeof(buf), fp) == NULL)
  1180.         {
  1181.         if (!feof(fp)) /* was it an error other than EOF? */
  1182.            fputs("Warning: error reading filtering data, filtering may be incomplete.\n",stderr) ;
  1183.         break ;
  1184.         }
  1185.      len = strlen(buf) ;
  1186.      if (len > 0 && buf[len-1] == '\n')
  1187.         buf[--len] = '\0' ;
  1188.      if (len > 1)
  1189.         {
  1190.         switch (buf[0])
  1191.            {
  1192.            case '+':
  1193.           includes = add_filter_info(includes,buf+1) ;
  1194.           break ;
  1195.            case '-':
  1196.           excludes = add_filter_info(excludes,buf+1) ;
  1197.           break ;
  1198.            case '#':        /* comment lines */
  1199.            default:
  1200.           break ;
  1201.            }
  1202.         }
  1203.      }
  1204.       fclose(fp) ;
  1205.       do_filter = TRUE ;
  1206.       }
  1207. }
  1208.  
  1209. /***********************************************/
  1210.  
  1211. int _Cdecl main(argc,argv)
  1212. int argc ;
  1213. char *argv[] ;
  1214. {
  1215.    int lines_per_page = -1 ;
  1216.    int total_lines = -1 ;
  1217.    int use_FF = TRUE ;
  1218.    int last_line ;
  1219.    int body_lines ;
  1220.    char *typeface = NULL ;
  1221.    char *summary_file = NULL ;
  1222.    char *formats_file = NULL ;
  1223.    char *filter_file = NULL ;
  1224.    char *last_page_num ;
  1225.    
  1226.    fputs("INTPRINT v", stderr) ;
  1227.    fputs(VERSION, stderr) ;
  1228.    fputs(" by Ralf Brown and others.  Donated to the Public Domain.\n",stderr) ;
  1229.    if (argc == 1 && isatty(0))
  1230.       usage() ;      /* give help if invoked with no args and keybd input */
  1231.    while (argc >= 2 && argv[1][0] == '-')
  1232.       {
  1233.       switch (argv[1][1])
  1234.      {
  1235.      case 'B':
  1236.         printer_bold = TRUE ;
  1237.         /* fall through to -b */
  1238.      case 'b':
  1239.         boldface = TRUE ;
  1240.         break ;
  1241.      case 'd':
  1242.         duplex = TRUE ;
  1243.         break ;
  1244.      case 'e':
  1245.         indent = 8 ;
  1246.         page_width = 87 ;  /* 96 - indent - 1 right margin */
  1247.         break ;
  1248.      case 'f':
  1249.         formats_file = argv[1]+2 ;
  1250.         break ;
  1251.      case 'F':
  1252.         filter_file = argv[1]+2 ;
  1253.         break ;
  1254.      case 'H':   /* page headers */
  1255.         do_headers = TRUE ;
  1256.         break ;
  1257.      case 'i':
  1258.         indent = atoi(argv[1]+2) ;
  1259.         break ;
  1260.      case 'I':
  1261.         IBM_chars = TRUE ;
  1262.         break ;
  1263.      case 'k':
  1264.         keep_divider_lines = TRUE ;
  1265.         break ;
  1266.      case 'l':
  1267.         lines_per_page = atoi(argv[1]+2) ;
  1268.         break ;
  1269.      case 'L':
  1270.         total_lines = atoi(argv[1]+2) ;
  1271.         break ;
  1272.      case 'm':
  1273.         multi_file = TRUE ;
  1274.         break ;
  1275.      case 'n':
  1276.         pages_printed = atoi(argv[1]+2) ;
  1277.         break ;
  1278.      case 'P':
  1279.         if (argv[1][2] == '?')
  1280.            display_printers() ;
  1281.         else
  1282.            select_printer(argv[1]+2) ;
  1283.         break ;
  1284.      case 'p':
  1285.         page_numbers = TRUE ;
  1286.         break ;
  1287.      case 'r':
  1288.         first_page = atoi(argv[1]+2) ;
  1289.         last_page_num = strchr(argv[1]+2, ':') ;
  1290.         last_page = last_page_num ? atoi(last_page_num+1) : 0 ;
  1291.         if (last_page == 0)
  1292.            last_page = ~0 ;
  1293.         break ;
  1294.      case 's':
  1295.         summary_file = argv[1]+2 ;
  1296.         break ;
  1297.      case 't':
  1298.         typeface = argv[1]+2 ;
  1299.         break ;
  1300.      case 'w':
  1301.         widow_length = atoi(argv[1]+2) ;
  1302.         break ;
  1303.      case 'x':
  1304.         include_index_lines = TRUE ;
  1305.         break ;
  1306.      default:
  1307.         usage() ;
  1308.      }
  1309.       argv++ ;
  1310.       argc-- ;
  1311.       }
  1312.    if (printer == NULL)
  1313.       select_printer("default") ;
  1314.    /* apply any necessary overrides to parameters */
  1315.    if (printer->indent != -1)
  1316.       indent = printer->indent ;
  1317.    if (lines_per_page < 0)
  1318.       lines_per_page = printer->lines_per_page ;
  1319.    if (total_lines <= 0)
  1320.       total_lines = printer->page_length ;
  1321.    if (page_width <= 0)
  1322.       page_width = printer->page_width ;
  1323.    if (printer->flag)
  1324.       *(printer->flag) = TRUE ;
  1325.    if (cstrlen(&printer->bold_on) == 0)     /* control sequences for bold? */
  1326.       printer_bold = FALSE ;        /* if not, don't try to use them */
  1327.  
  1328.    /* open the summary file, if any */
  1329.    if (summary_file && *summary_file)
  1330.       if ((summary = fopen(summary_file, pages_printed ? "a":"w")) != NULL)
  1331.      do_summary = TRUE ;
  1332.       else
  1333.      fputs("unable to open summary file\n", stderr) ;
  1334.    /* open the data formats file, if any */
  1335.    if (formats_file && *formats_file)
  1336.       if ((formats = fopen(formats_file, pages_printed ? "a":"w")) != NULL)
  1337.      do_formats = TRUE ;
  1338.       else
  1339.      fputs("unable to open formats file\n", stderr) ;
  1340.    /* initialize filtering data, if specified */
  1341.    if (filter_file && *filter_file)
  1342.       build_filter_lists(filter_file) ;
  1343.    if (total_lines <= lines_per_page)
  1344.       {
  1345.       total_lines = lines_per_page ;
  1346.       use_FF = TRUE ;
  1347.       }
  1348.    else
  1349.       use_FF = FALSE ;
  1350.    if (argc == 2 || argc == 3)
  1351.       {
  1352.       input_file = argv[1] ;
  1353.       infile = fopen(input_file,"r") ;
  1354.       if (infile == NULL)
  1355.      fatal("unable to open input file") ;
  1356.       if (argc == 3)
  1357.      {
  1358.      outfile = fopen(argv[2],(pages_printed?"a":"w")) ;
  1359.      if (outfile == NULL)
  1360.         fatal("unable to open output file") ;
  1361.      }
  1362.       else
  1363.      outfile = stdout ;
  1364.       }
  1365.    else
  1366.       usage() ;
  1367.    if (lines_per_page > MAXPAGE)
  1368.       {
  1369.       fputs("Surely you jest!  I can't handle pages that long.\n\n", stderr) ;
  1370.       usage() ;
  1371.       }
  1372.    else if (lines_per_page == 0) /* infinite page? */
  1373.       {
  1374.       widow_length = 0 ;
  1375.       if (total_lines <= 0)
  1376.      total_lines = MAXPAGE ;
  1377.       lines_per_page = total_lines ;
  1378.       use_FF = do_headers = page_numbers = FALSE ;
  1379.       }
  1380.    else
  1381.       {
  1382.       if (lines_per_page < 20)
  1383.      {
  1384.      fputs("Surely your printer can handle at least 20 lines per page!\n",stderr) ;
  1385.      fputs("Adjusting page length....\n",stderr) ;
  1386.      lines_per_page = 20 ;
  1387.      }
  1388.       if (widow_length < 3 || widow_length > lines_per_page / 2)
  1389.          {
  1390.      fputs("Widow lines (-w) must be set to at least 3 and at most one-half of the\n",stderr) ;
  1391.      fputs("page length.  Using default of 10 lines.\n",stderr) ;
  1392.      widow_length = 10 ;
  1393.      }
  1394.       }
  1395. #ifdef __TURBOC__
  1396.    setvbuf(infile,NULL,_IOFBF,10240) ;    /* use larger disk buffers */
  1397.    setvbuf(outfile,NULL,_IOFBF,10240) ; /* for better performance */
  1398.    if (do_summary)
  1399.       setvbuf(summary,NULL,_IOFBF,4096) ;
  1400.    if (do_formats)
  1401.       setvbuf(formats,NULL,_IOFBF,4096) ;
  1402. #endif /* __TURBOC__ */
  1403.    /* set up the printer */
  1404.    fputcstr(&printer->init1,outfile) ;
  1405.    fputcstr(&printer->init2,outfile) ;
  1406.    if (printer->set_typeface)
  1407.       (*printer->set_typeface)(outfile,typeface) ;
  1408.    if (duplex)
  1409.       {
  1410.       fputcstr(&printer->duplex_on,outfile) ;
  1411.       if ((pages_printed % 2) == 1)    /* next page odd or even? */
  1412.      fputcstr(&printer->marginl,outfile) ;    /* even */
  1413.       else
  1414.      fputcstr(&printer->marginr,outfile) ;    /* odd */
  1415.       }
  1416.    else
  1417.       fputcstr(&printer->marginc,outfile) ;    /* non-duplex, so center */
  1418.    /* start the summary file */
  1419.    if (do_summary && pages_printed == 0)
  1420.       {          /* create header, but only on first part */
  1421.       /* set up the printer */
  1422.       fputcstr(&printer->init1,summary) ;
  1423.       fputcstr(&printer->init2,summary) ;
  1424.       fputcstr(&printer->marginc,summary) ;
  1425.       indent_line(summary) ;
  1426.       fputs("\t\t\t\tInterrupt Summary\n",summary) ;
  1427.       indent_line(summary) ;
  1428.       fputs("\t\t\t\t", summary) ;
  1429.       (*printer->put_line)(summary,17) ;
  1430.       fputs("\n\n",summary) ;
  1431.       indent_line(summary) ;
  1432.       fputs("INT AH AL", summary) ;
  1433.       if (page_numbers)
  1434.      fputs(" Page", summary) ;
  1435.       fputs("\t\t\tDescription\n", summary) ;
  1436.       indent_line(summary) ;
  1437.       (*printer->put_line)(summary,page_width) ;
  1438.       fputc('\n', summary) ;
  1439.       }
  1440.    /* start the data formats file */
  1441.    if (do_formats && pages_printed == 0)
  1442.       {          /* create header, but only on first part */
  1443.       /* set up the printer */
  1444.       fputcstr(&printer->init1,formats) ;
  1445.       fputcstr(&printer->init2,formats) ;
  1446.       fputcstr(&printer->marginc,formats) ;
  1447.       indent_line(formats) ;
  1448.       fputs("\t\t\tData Structure Formats\n", formats) ;
  1449.       indent_line(formats) ;
  1450.       fputs("\t\t\t", formats) ;
  1451.       (*printer->put_line)(formats,22) ;
  1452.       fputs("\n\n", formats) ;
  1453.       indent_line(formats) ;
  1454.       fputs("INT AH AL", formats) ;
  1455.       if (page_numbers)
  1456.      fputs(" Page", formats) ;
  1457.       fputs("\t\tData Structure\n", formats) ;
  1458.       }
  1459.    if (page_numbers)
  1460.       body_lines = lines_per_page - 2 ;
  1461.    else
  1462.       body_lines = lines_per_page ;
  1463.    if (do_headers)
  1464.       body_lines -= 2 ;
  1465.    last_line = 0 ;
  1466.    while (!feof(infile) && !out_of_files)
  1467.       {
  1468.       fill_buffer(last_line,body_lines) ;
  1469.       last_line = find_page_break(body_lines) ;
  1470.       print_buffer(last_line,lines_per_page,total_lines,use_FF) ;
  1471.       }
  1472.    if (last_line < body_lines)
  1473.       {
  1474.       int i ;
  1475.       
  1476.       for (i = last_line ; i < body_lines ; i++)
  1477.      strcpy(buffer[i-last_line], buffer[i]) ;
  1478.       print_buffer(body_lines-last_line,lines_per_page,total_lines,use_FF) ;
  1479.       }
  1480.    /* reset the printer */
  1481.    fputcstr(&printer->term1,outfile) ;
  1482.    fputcstr(&printer->term2,outfile) ;
  1483.    fflush(outfile) ;
  1484.    itoa(pages_printed, num, 10) ;
  1485.    fputs(num, stderr) ;
  1486.    fputs(" pages\n", stderr) ;
  1487.    if (do_summary)
  1488.       {
  1489.       /* reset the printer */
  1490.       fputcstr(&printer->term1,summary) ;
  1491.       fputcstr(&printer->term2,summary) ;
  1492.       fclose(summary) ;
  1493.       }
  1494.    if (do_formats)
  1495.       {
  1496.       /* reset the printer */
  1497.       fputcstr(&printer->term1,formats) ;
  1498.       fputcstr(&printer->term2,formats) ;
  1499.       fclose(formats) ;
  1500.       }
  1501.    fclose(infile) ;
  1502.    return 0 ;
  1503. }
  1504.